package com.zhou.spring.cloud.balancer.feign.config;

import com.alibaba.cloud.commons.lang.StringUtils;
import feign.*;
import feign.auth.BasicAuthRequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import feign.form.spring.SpringFormEncoder;
import feign.optionals.OptionalDecoder;
import org.slf4j.MDC;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.DefaultFeignLoggerFactory;
import org.springframework.cloud.openfeign.FeignLoggerFactory;
import org.springframework.cloud.openfeign.support.AbstractFormWriter;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class CustomFeignConfiguration {

    @Value("${testValue:}")
    private String testValue;

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Retryer feignRetryer() {
        return new Retryer.Default(1000, 1000, 2);
    }

    @Bean
    public Decoder feignDecoder() {
        return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
    }

    @Bean
    public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        return springEncoder(formWriterProvider);
    }

    @Bean
    public FeignLoggerFactory feignLoggerFactory() {
        return new DefaultFeignLoggerFactory(null);
    }

    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

    //不配置则会使用默认的
    @Bean
    public ErrorDecoder errorDecoder() {
        return new ErrorDecoder.Default();
    }

    @Bean
    public Request.Options requestOptions() {
        return new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
    }

    /**
     * 请求拦截器
     * 也可以自定义，对于全局的认证
     *
     * @return
     */
    @Bean
    public RequestInterceptor requestInterceptor() {
        return new BasicAuthRequestInterceptor("username", "password");
    }

    public static final String TRACEID = "traceId";

    @Bean()
    public RequestInterceptor headerInterceptor() {
        return requestTemplate -> {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            requestTemplate.header("Authorization", request.getHeader("Authorization"));
            if (StringUtils.isNotEmpty(MDC.get(TRACEID))) {
                requestTemplate.header(TRACEID, MDC.get(TRACEID));
            }
        };
    }

    //下面这三个bean，基本上不用配置,手动的时候，可能会用到
    //QueryMapEncoder 默认的已经够使用了 ，ExceptionPropagationPolicy 是否要传递原始异常  SpringMvcContract
    //    @Before
    //    public void init() {
    ////        String url = "http://172.22.115.251:8080/flow-platform/";
    ////        String url = "http://localhost:28080/flow-platform/";
    //        String url = "https://qinqing.zhengzhou.gov.cn:4431/qinqing/flow-platform/";
    //        client = Feign
    //                .builder()
    //                .contract(new SpringMvcContract())
    //                .decoder(new SpringDecoder(objectFactory))
    //                .encoder(new SpringFormEncoder(new SpringEncoder(objectFactory)))
    //                .logLevel(Logger.Level.FULL)
    //                .logger(new Slf4jLogger(FlowClientHttpServiceTest.class))
    //                .target(FlowClientHttpService.class, url + API_PUBLIC_PATH);
    //    }

    /*@Bean
    public FeignBuilderCustomizer feignBuilderCustomizer() {
        return new FeignBuilderCustomizer() {
            @Override
            public void customize(Feign.Builder builder) {
                builder.addCapability(new Capability() {
                    @Override
                    public Client enrich(Client client) {
                        return client;
//                        return new AClient(client);
                    }
                });
            }
        };
    }*/


    private class AClient implements Client {

        public AClient(Client client) {
            if (!(client instanceof Client.Default)) {
                throw new RuntimeException(
                        "Test is chaining invokations, expected Default Client instace here");
            }
        }

        @Override
        public Response execute(Request request, Request.Options options) throws IOException {
            return null;
        }

    }

    private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        return new SpringEncoder(new SpringFormEncoder(), this.messageConverters);
    }

}
